/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-enum-comparison */
import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
  HttpStatus,
  Inject,
} from '@nestjs/common';
import { AppLoggerService } from '../logger/logger.service';
import { Request, Response } from 'express';
import { ErrorCode } from '../constants/error-code.enum';

/**
 * HTTP异常过滤器
 * 用于统一处理HTTP异常
 */
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  @Inject(AppLoggerService)
  private readonly logger: AppLoggerService;

  constructor() {
    this.logger?.setContext?.('HttpExceptionFilter');
  }

  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();

    const exceptionResponse = exception.getResponse() as any;

    // 获取错误信息
    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
    let errorMessage = exceptionResponse.message || exception.message;

    // 处理class-validator验证错误
    if (status === HttpStatus.BAD_REQUEST && Array.isArray(errorMessage)) {
      errorMessage = errorMessage[0];
    }

    // 根据状态码映射错误码
    let errorCode = ErrorCode.COMMON_ERROR;
    switch (status) {
      case HttpStatus.BAD_REQUEST:
        errorCode = ErrorCode.PARAMS_ERROR;
        break;
      case HttpStatus.UNAUTHORIZED:
        errorCode = ErrorCode.UNAUTHORIZED;
        break;
      case HttpStatus.FORBIDDEN:
        errorCode = ErrorCode.FORBIDDEN;
        break;
      case HttpStatus.NOT_FOUND:
        errorCode = ErrorCode.NOT_FOUND;
        break;
      case HttpStatus.INTERNAL_SERVER_ERROR:
        errorCode = ErrorCode.INTERNAL_SERVER_ERROR;
        break;
      default:
        errorCode = ErrorCode.COMMON_ERROR;
    }

    // 构建错误响应
    const errorResponse = {
      code: errorCode,
      result: null,
      msg: Array.isArray(errorMessage) ? errorMessage[0] : errorMessage,
      path: request.url,
      timestamp: new Date().toISOString(),
    };

    // 记录错误日志
    this.logger.error(
      `${request.method} ${request.url} ${status} - ${JSON.stringify(errorResponse)}`,
      exception.stack,
    );

    response.status(status).json(errorResponse);
  }
}

/**
 * 全局异常过滤器
 * 用于统一处理所有异常
 */
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
  @Inject(AppLoggerService)
  private readonly logger: AppLoggerService;

  constructor() {
    this.logger?.setContext?.('AllExceptionsFilter');
  }

  catch(exception: any, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();

    // 默认状态码和错误码
    let status = HttpStatus.INTERNAL_SERVER_ERROR;
    let errorCode = ErrorCode.INTERNAL_SERVER_ERROR;
    let errorMessage = '服务器内部错误';

    // 处理class-validator验证错误
    if (
      exception?.response?.statusCode === 400 &&
      Array.isArray(exception?.response?.message)
    ) {
      status = HttpStatus.BAD_REQUEST;
      errorCode = ErrorCode.PARAMS_ERROR;
      errorMessage = exception.response.message[0];
    } else if (exception instanceof HttpException) {
      // 处理HTTP异常
      status = exception.getStatus();
      const exceptionResponse = exception.getResponse() as any;
      errorMessage = exceptionResponse.message || exception.message;

      // 根据状态码映射错误码
      switch (status) {
        case HttpStatus.BAD_REQUEST:
          errorCode = ErrorCode.PARAMS_ERROR;
          break;
        case HttpStatus.UNAUTHORIZED:
          errorCode = ErrorCode.UNAUTHORIZED;
          break;
        case HttpStatus.FORBIDDEN:
          errorCode = ErrorCode.FORBIDDEN;
          break;
        case HttpStatus.NOT_FOUND:
          errorCode = ErrorCode.NOT_FOUND;
          break;
        default:
          errorCode = ErrorCode.COMMON_ERROR;
      }
    }

    // 构建错误响应
    const errorResponse = {
      code: errorCode,
      result: null,
      msg: Array.isArray(errorMessage) ? errorMessage[0] : errorMessage,
      path: request.url,
      timestamp: new Date().toISOString(),
    };

    // 记录错误日志
    this.logger.error(
      `${request.method} ${request.url} ${status} - ${JSON.stringify(errorResponse)}`,
      exception.stack,
    );

    response.status(status).json(errorResponse);
  }
}
